#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include "compiler/lexer.h"
#include "compiler/parser.h"

// Test CREATE TABLE statement parsing
void testCreateTableParsing() {
    std::cout << "Running CREATE TABLE statement parsing test..." << std::endl;
    
    try {
        std::string sql = "CREATE TABLE users (id INT, name VARCHAR, age INT);";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        std::unique_ptr<AST::Statement> statement = parser.parse();
        
        // Check if the statement is a CreateTableStmt
        AST::CreateTableStmt* createTableStmt = dynamic_cast<AST::CreateTableStmt*>(statement.get());
        if (!createTableStmt) {
            std::cerr << "Failed to parse CREATE TABLE statement" << std::endl;
            exit(1);
        }
        
        // Verify the parsed data
        std::cout << "Parsed statement: " << statement->toString() << std::endl;
        
        // Check table name
        if (createTableStmt->tableName != "users") {
            std::cerr << "Incorrect table name: " << createTableStmt->tableName << std::endl;
            exit(1);
        }
        
        // Check columns
        if (createTableStmt->columns.size() != 3) {
            std::cerr << "Incorrect number of columns: " << createTableStmt->columns.size() << std::endl;
            exit(1);
        }
        
        // Check specific column details
        if (createTableStmt->columns[0].first != "id" || createTableStmt->columns[0].second != "INT") {
            std::cerr << "Incorrect column definition for id" << std::endl;
            exit(1);
        }
        
        if (createTableStmt->columns[1].first != "name" || createTableStmt->columns[1].second != "VARCHAR") {
            std::cerr << "Incorrect column definition for name" << std::endl;
            exit(1);
        }
        
        if (createTableStmt->columns[2].first != "age" || createTableStmt->columns[2].second != "INT") {
            std::cerr << "Incorrect column definition for age" << std::endl;
            exit(1);
        }
        
        std::cout << "CREATE TABLE parsing test passed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(1);
    }
}

// Test INSERT statement parsing
void testInsertParsing() {
    std::cout << "Running INSERT statement parsing test..." << std::endl;
    
    try {
        std::string sql = "INSERT INTO users (id, name, age) VALUES (1, 'John Doe', 30);";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        std::unique_ptr<AST::Statement> statement = parser.parse();
        
        // Check if the statement is an InsertStmt
        AST::InsertStmt* insertStmt = dynamic_cast<AST::InsertStmt*>(statement.get());
        if (!insertStmt) {
            std::cerr << "Failed to parse INSERT statement" << std::endl;
            exit(1);
        }
        
        // Verify the parsed data
        std::cout << "Parsed statement: " << statement->toString() << std::endl;
        
        // Check table name
        if (insertStmt->tableName != "users") {
            std::cerr << "Incorrect table name: " << insertStmt->tableName << std::endl;
            exit(1);
        }
        
        // Check columns
        if (insertStmt->columns.size() != 3) {
            std::cerr << "Incorrect number of columns: " << insertStmt->columns.size() << std::endl;
            exit(1);
        }
        
        // Check values
        if (insertStmt->values.size() != 3) {
            std::cerr << "Incorrect number of values: " << insertStmt->values.size() << std::endl;
            exit(1);
        }
        
        std::cout << "INSERT parsing test passed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(1);
    }
}

// Test SELECT statement parsing
void testSelectParsing() {
    std::cout << "Running SELECT statement parsing test..." << std::endl;
    
    try {
        std::string sql = "SELECT id, name FROM users WHERE age > 18;";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        std::unique_ptr<AST::Statement> statement = parser.parse();
        
        // Check if the statement is a SelectStmt
        AST::SelectStmt* selectStmt = dynamic_cast<AST::SelectStmt*>(statement.get());
        if (!selectStmt) {
            std::cerr << "Failed to parse SELECT statement" << std::endl;
            exit(1);
        }
        
        // Verify the parsed data
        std::cout << "Parsed statement: " << statement->toString() << std::endl;
        
        // Check table name
        if (selectStmt->tableName != "users") {
            std::cerr << "Incorrect table name: " << selectStmt->tableName << std::endl;
            exit(1);
        }
        
        // Check columns
        if (selectStmt->columns.size() != 2) {
            std::cerr << "Incorrect number of columns: " << selectStmt->columns.size() << std::endl;
            exit(1);
        }
        
        // Check specific column names
        if (selectStmt->columns[0] != "id" || selectStmt->columns[1] != "name") {
            std::cerr << "Incorrect column names" << std::endl;
            exit(1);
        }
        
        // Check where clause
        if (!selectStmt->whereClause) {
            std::cerr << "Missing WHERE clause" << std::endl;
            exit(1);
        }
        
        std::cout << "SELECT parsing test passed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(1);
    }
}

// Test DELETE statement parsing
void testDeleteParsing() {
    std::cout << "Running DELETE statement parsing test..." << std::endl;
    
    try {
        std::string sql = "DELETE FROM users WHERE id = 1;";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        std::unique_ptr<AST::Statement> statement = parser.parse();
        
        // Check if the statement is a DeleteStmt
        AST::DeleteStmt* deleteStmt = dynamic_cast<AST::DeleteStmt*>(statement.get());
        if (!deleteStmt) {
            std::cerr << "Failed to parse DELETE statement" << std::endl;
            exit(1);
        }
        
        // Verify the parsed data
        std::cout << "Parsed statement: " << statement->toString() << std::endl;
        
        // Check table name
        if (deleteStmt->tableName != "users") {
            std::cerr << "Incorrect table name: " << deleteStmt->tableName << std::endl;
            exit(1);
        }
        
        // Check where clause
        if (!deleteStmt->whereClause) {
            std::cerr << "Missing WHERE clause" << std::endl;
            exit(1);
        }
        
        std::cout << "DELETE parsing test passed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(1);
    }
}

// Test parsing multiple statements
void testMultipleStatementsParsing() {
    std::cout << "Running multiple statements parsing test..." << std::endl;
    
    try {
        std::string sql = "CREATE TABLE products (id INT, name VARCHAR); INSERT INTO products VALUES (1, 'Laptop'); SELECT * FROM products;";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        std::vector<std::unique_ptr<AST::Statement>> statements = parser.parseMultipleStatements();
        
        // Check number of statements
        if (statements.size() != 3) {
            std::cerr << "Incorrect number of statements: " << statements.size() << std::endl;
            exit(1);
        }
        
        // Check statement types
        if (!dynamic_cast<AST::CreateTableStmt*>(statements[0].get())) {
            std::cerr << "First statement is not a CREATE TABLE statement" << std::endl;
            exit(1);
        }
        
        if (!dynamic_cast<AST::InsertStmt*>(statements[1].get())) {
            std::cerr << "Second statement is not an INSERT statement" << std::endl;
            exit(1);
        }
        
        if (!dynamic_cast<AST::SelectStmt*>(statements[2].get())) {
            std::cerr << "Third statement is not a SELECT statement" << std::endl;
            exit(1);
        }
        
        std::cout << "Multiple statements parsing test passed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(1);
    }
}

// Test error handling in parser
void testParserErrorHandling() {
    std::cout << "Running parser error handling test..." << std::endl;
    
    try {
        // Invalid SQL: missing table name in CREATE TABLE
        std::string sql = "CREATE TABLE (id INT);";
        Lexer lexer(sql);
        std::vector<Token> tokens = lexer.tokenize();
        
        Parser parser(tokens);
        
        // This should throw a ParserError
        parser.parse();
        
        // If we get here, the error wasn't caught
        std::cerr << "Parser did not catch invalid SQL syntax" << std::endl;
        exit(1);
        
    } catch (const ParserError& e) {
        // This is expected
        std::cout << "Expected parser error caught: " << e.what() << std::endl;
        std::cout << "Parser error handling test passed!" << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Unexpected error: " << e.what() << std::endl;
        exit(1);
    }
}

int main() {
    std::cout << "Running Parser unit tests..." << std::endl;
    std::cout << "==================================" << std::endl;
    
    // Run individual tests
    testCreateTableParsing();
    testInsertParsing();
    testSelectParsing();
    testDeleteParsing();
    testMultipleStatementsParsing();
    testParserErrorHandling();
    
    std::cout << "==================================" << std::endl;
    std::cout << "All Parser tests passed successfully!" << std::endl;
    return 0;
}